import { MathUtils, Vector3 } from "three";
import GeoUtils from "../../utils/GeoUtils";
import Const from "../../application/constants/Const";
import Pixel from "./Pixel";
import GPSUtils from "../../utils/GPSUtils";
import Config from "../../application/constants/Config";
/**
 * 地图中定位一个点
 */
class Point extends Vector3 {
    public EPSGType: string;
    /**
     * 
     * @param x x坐标
     * @param y y坐标
     * @param z z坐标
     * @param EPSGType 表示坐标类型，有三种类型：4326，3857和gcj02,默认是4326
     */
    constructor(x: number = 0, y: number = 0, z: number = 0, EPSGType: string = Const.EPSGType.EPSG84) {
        super(x, y, z);
        this.EPSGType = EPSGType;
    }
    public set(x: number, y: number, z: number = 0, EPSGType: string = Const.EPSGType.EPSG84) {
        super.set(x, y, z);
        this.EPSGType = EPSGType;
        return this;
    }
    /**
    * 获取XYZ信息
    */
    public getXYZ() {
        return { x: this.x, y: this.y, z: this.z };
    }
    /**
    * 点进行坐标转换
    * @param EPSGType EPSG名称，当前点在3857，4326和4326坐标系之间转换。
    */
    public changeEPSGType(EPSGType: string) {
        if (this.EPSGType != EPSGType) {
            if (EPSGType == Const.EPSGType.EPSG84 && Config.Map.geographySystem == Const.EPSGType.EPSG84) {//当前地图用的是84地理坐标系，把点转换到84坐标系
                if(this.EPSGType == Const.EPSGType.EPSGWeb){ //如果之前是web墨卡托坐标系
                    this.x = GeoUtils.WebtoP84_X(this.x);
                    this.y = GeoUtils.WebtoP84_Y(this.y);
                }else if(this.EPSGType == Const.EPSGType.GCJ02){ //如果之前是GCJ02坐标系
                     let wgs84lnglat = GPSUtils.gcj_decrypt_exact(this.x, this.y); //GCJ02坐标转换到84坐标
                     this.x = wgs84lnglat[0];
                     this.y = wgs84lnglat[1];
                }
            } else if (EPSGType == Const.EPSGType.EPSGWeb && Config.Map.geographySystem == Const.EPSGType.EPSG84) {//当前地图用的是84地理坐标系，把点转换到web墨卡托坐标系
                if(this.EPSGType == Const.EPSGType.EPSG84){ //如果之前是84坐标系
                    this.x = GeoUtils.P84ToWeb_X(this.x);
                    this.y = GeoUtils.P84ToWeb_Y(this.y);
                }else if(this.EPSGType == Const.EPSGType.GCJ02){ //如果之前是GCJ02坐标系
                    let wgs84lnglat = GPSUtils.gcj_decrypt_exact(this.x, this.y); //GCJ02坐标转换到84坐标
                    this.x = GeoUtils.P84ToWeb_X(wgs84lnglat[0]);
                    this.y = GeoUtils.P84ToWeb_Y(wgs84lnglat[1]);
                }
            } else if(EPSGType == Const.EPSGType.GCJ02 && Config.Map.geographySystem == Const.EPSGType.EPSG84){//当前地图用的是84地理坐标系，把点转换到gcj02坐标系
                if(this.EPSGType == Const.EPSGType.EPSGWeb){ //如果之前是web墨卡托坐标系
                    let wgsLnglat = GeoUtils.WebtoP84(this.x, this.y);
                    let gcj02Lnglat = GPSUtils.gcj_encrypt(wgsLnglat.x, wgsLnglat.y)
                    this.x = gcj02Lnglat[0];
                    this.y = gcj02Lnglat[1];
                }else if(this.EPSGType == Const.EPSGType.EPSG84){ //如果之前是84坐标系
                    let gcj02Lnglat = GPSUtils.gcj_encrypt(this.x, this.y)
                    this.x = gcj02Lnglat[0];
                    this.y = gcj02Lnglat[1];
                }
            }


           else if (EPSGType == Const.EPSGType.EPSG84 && Config.Map.geographySystem == Const.EPSGType.GCJ02) {//当前地图用的是gcj02地理坐标系，把点转换到84坐标系
                if(this.EPSGType == Const.EPSGType.EPSGWeb){ //如果之前是web墨卡托坐标系
                    let gcj02Lnglat = GeoUtils.WebtoP84(this.x, this.y);
                    let wgsLnglat = GPSUtils.gcj_decrypt_exact(gcj02Lnglat.x, gcj02Lnglat.y);

                    this.x = wgsLnglat[0];
                    this.y = wgsLnglat[1];
                }else if(this.EPSGType == Const.EPSGType.GCJ02){ //如果之前是GCJ02坐标系
                     let wgs84lnglat = GPSUtils.gcj_decrypt_exact(this.x, this.y); //GCJ02坐标转换到84坐标
                     this.x = wgs84lnglat[0];
                     this.y = wgs84lnglat[1];
                }
            } else if (EPSGType == Const.EPSGType.EPSGWeb && Config.Map.geographySystem == Const.EPSGType.GCJ02) {//当前地图用的是gcj02地理坐标系，把点转换到web墨卡托坐标系
                if(this.EPSGType == Const.EPSGType.EPSG84){ //如果之前是84坐标系
                    let gcj02Lnglat = GPSUtils.gcj_encrypt(this.x, this.y);

                    this.x = GeoUtils.P84ToWeb_X(gcj02Lnglat[0]);
                    this.y = GeoUtils.P84ToWeb_Y(gcj02Lnglat[1]);
                }else if(this.EPSGType == Const.EPSGType.GCJ02){ //如果之前是GCJ02坐标系
                    // let wgs84lnglat = GPSUtils.gcj_decrypt_exact(this.x, this.y); //GCJ02坐标转换到84坐标
                    this.x = GeoUtils.P84ToWeb_X(this.x);
                    this.y = GeoUtils.P84ToWeb_Y(this.y);
                }
            } else if(EPSGType == Const.EPSGType.GCJ02 && Config.Map.geographySystem == Const.EPSGType.GCJ02){//当前地图用的是gcj02地理坐标系，把点转换到gcj02坐标系
                if(this.EPSGType == Const.EPSGType.EPSGWeb){ //如果之前是web墨卡托坐标系
                    let wgsLnglat = GeoUtils.WebtoP84(this.x, this.y);
                    // let gcj02Lnglat = GPSUtils.gcj_encrypt(wgsLnglat.x, wgsLnglat.y)
                    this.x = wgsLnglat.x;
                    this.y = wgsLnglat.y;
                }else if(this.EPSGType == Const.EPSGType.EPSG84){ //如果之前是84坐标系
                    // let gcj02Lnglat = GPSUtils.gcj_encrypt(this.x, this.y)
                    let gcj02Lnglat = GPSUtils.gcj_encrypt(this.x, this.y)
                    this.x = gcj02Lnglat[0];
                    this.y = gcj02Lnglat[1];
                }
            }
            else {
                console.log('未知类型转换:' + this.EPSGType + "=>" + EPSGType);
            }
            this.EPSGType = EPSGType;
        }
        return this;
    }

    // @ts-ignore
    public clone() {
        let newPoint = new Point();
        Object.assign(newPoint, this);
        return newPoint;
        // return new Point(this.x, this.y, this.z, this.EPSGType);
    }

    /**
     * 将坐标点转换为地图上的web墨卡托坐标
     * @returns 
     */
    public toVector3(): Vector3 {
        let webMercator = new Vector3;
        if (this.EPSGType === Const.EPSGType.EPSG84) {
            let xy;
            xy = GeoUtils.P84toWeb(this.x, this.y);
            webMercator.x = xy.x;
            webMercator.y = xy.y;
            webMercator.z = this.z;
            this.EPSGType = Const.EPSGType.EPSGWeb;
        }
        return new Vector3(webMercator.x, webMercator.y, webMercator.z);
    }

    public offset(w: number, s: number, h: number = 0) {
        this.x += w;
        this.y += s;
        this.z += h;
        return this;
    }
    public fromArray(array: Array<number>, offset: number = 0) {
        if (array.length < 2) return this;
        this.x = array[offset];
        this.y = array[offset + 1];
        this.z = array[offset + 2] ? array[offset + 2] : 0;
        return this;
    }
    /** 相减 */
    public sub(point: Point | Vector3) {
        let clone = point.clone();
        if (clone instanceof Point) clone = clone.changeEPSGType(this.EPSGType);
        this.x -= clone.x;
        this.y -= clone.y;
        this.z -= clone.z;
        return this;
    }
    /**相加 */
    public add(point: Point | Vector3) {
        if (point instanceof Point && point.EPSGType == Const.EPSGType.EPSG84)
            point.toEPSGWeb();
        this.x += point.x;
        this.y += point.y;
        this.z += point.z;
        return this;
    }

    public divideBy(scale: number): Point {
        return new Point(this.x / scale, this.y / scale, this.z, this.EPSGType);
    }
    /** 计算距离 */
    public distance(point: Point | Array<Point>): number {
        if (point instanceof Point) {
            let otherClone = point.clone().toEPSGWeb();
            let curClone = this.clone().toEPSGWeb();
            let z1 = 0;
            let z2 = 0;
            let Lat1 = MathUtils.degToRad(otherClone.y);
            let Lat2 = MathUtils.degToRad(curClone.y);
            let a = Lat1 - Lat2;
            let b = MathUtils.degToRad(otherClone.x) - MathUtils.degToRad(curClone.x);
            let s = 2.27 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(Lat1) * Math.cos(Lat2) * Math.pow(Math.sin(b / 2), 2)));
            s = s * 6378137.0;
            s = Math.round(s * 10000) / 10000;
            let dealZ = Math.abs(z1 - z2);
            if (dealZ != 0) s = Math.sqrt(s * s + dealZ * dealZ);
            return s;
        } else {
            let first = point.shift();
            if (point.length === 0) {
                return this.distance(first);
            } else {
                return this.distance(first) + first.distance(point);
            }
        }
    }
    public equals(point: Point): boolean {
        let clone = point.clone().changeEPSGType(this.EPSGType);
        return Math.abs(this.x - clone.x) < 0.0001 && Math.abs(this.y - clone.y) < 0.0001 && Math.abs(this.z - clone.z) < 0.0001;
    }

    public fromVector3(pos: Vector3) {
        let point = {
            x: pos.x,
            y: pos.y
        };
        if (this.EPSGType === Const.EPSGType.EPSGWeb) {
            point = GeoUtils.WebtoP84(pos.x, pos.y);
            this.EPSGType = Const.EPSGType.EPSG84;
        }

        this.x = point.x;
        this.y = point.y;
        this.z = pos.z;
        return this;
    }

    /**直接从当前的经纬度转换到web墨卡托坐标，不考虑当前地图的地理坐标系*/
    public toEPSGWeb2(){
        if (this.EPSGType == Const.EPSGType.EPSGWeb) return this;
        else if (this.EPSGType === Const.EPSGType.EPSG84) {
            let xy = GeoUtils.P84toWeb(this.x, this.y);
            this.x = xy.x;
            this.y = xy.y;
            this.EPSGType = Const.EPSGType.EPSGWeb;
            return this;
        }
    }

    /** 根据当前地图的地理坐标系转Web墨卡托坐标 */
    public toEPSGWeb() {
         this.changeEPSGType(Const.EPSGType.EPSGWeb);
        return this;
    }

     /**直接从当前的web墨卡托坐标转换到84坐标，不考虑当前地图的地理坐标系*/
    public toWgs842(){
    if (this.EPSGType == Const.EPSGType.EPSG84) return this;
        else if (this.EPSGType === Const.EPSGType.EPSGWeb) {
            let xy = GeoUtils.WebtoP84(this.x, this.y);
            this.x = xy.x;
            this.y = xy.y;
            this.EPSGType = Const.EPSGType.EPSG84;
            return this;
        }
    }

    /** 根据当前地图的地理坐标系转84经纬度坐标 */
    public toWGS84() {
        this.changeEPSGType(Const.EPSGType.EPSG84);
        return this;
    }

    /** 根据当前地图的地理坐标系转到gcj02经纬度坐标 */
    public toGcj02(){
         this.changeEPSGType(Const.EPSGType.GCJ02);
        return this;
    }

     /** 转地理经纬度坐标 */
    public toGeography() {
        if (this.EPSGType == Config.Map.geographySystem) return this;
        this.changeEPSGType(Config.Map.geographySystem);
        return this;
    }

    public toString(): string {
        return this.x + ',' + this.y + ',' + this.z;
    }

    public toPixel(): Pixel {
        let v3 = this.toVector3();
        return new Pixel(v3.x, v3.y, v3.z);
    }
}
export { Point }